package com.ethink.warehouse.facade.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ethink.framework.common.constant.CommonRespCode;
import com.ethink.framework.common.exception.BusinessException;
import com.ethink.warehouse.api.MateInventoryTypeChangeLogFacade;
import com.ethink.warehouse.api.enums.LogisticsTraceDetailOrderTypeEnum;
import com.ethink.warehouse.api.enums.MateInventoryTypeChangeLogOrderStatusEnum;
import com.ethink.warehouse.api.enums.SubjectEnum;
import com.ethink.warehouse.api.info.MateInventoryTypeChangeLogInfo;
import com.ethink.warehouse.api.info.MateInventoryTypeChangeLogModeInfo;
import com.ethink.warehouse.api.request.*;
import com.ethink.warehouse.api.response.MateInventoryTypeChangeLogAddResponse;
import com.ethink.warehouse.api.response.MateInventoryTypeChangeLogDeleteResponse;
import com.ethink.warehouse.api.response.MateInventoryTypeChangeLogGetDetailResponse;
import com.ethink.warehouse.api.response.MateInventoryTypeChangeLogUpdateResponse;
import com.ethink.warehouse.common.entity.MateInventoryTypeChangeLog;
import com.ethink.warehouse.common.entity.MateInventoryTypeChangeLogDetail;
import com.ethink.warehouse.common.mapper.MateInventoryTypeChangeLogDetailMapper;
import com.ethink.warehouse.common.mapper.MateInventoryTypeChangeLogMapper;
import com.ethink.warehouse.manager.MateInventoryManager;
import com.ethink.warehouse.service.MateInventoryTypeChangeLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 库存状态变更 Facade接口实现
 *
 * @author default
 * @date 2023-01-14
 */
@RestController
@Slf4j
@RequestMapping("warehouse-service/facade/v1/mateInventoryTypeChangeLog")
public class MateInventoryTypeChangeLogFacadeImpl implements MateInventoryTypeChangeLogFacade {


    @Autowired
    private MateInventoryTypeChangeLogMapper mateInventoryTypeChangeLogMapper;
    @Autowired
    private MateInventoryTypeChangeLogDetailMapper mateInventoryTypeChangeLogDetailMapper;
    @Autowired
    private MateInventoryTypeChangeLogService mateInventoryTypeChangeLogService;
    @Autowired
    private MateInventoryManager mateInventoryManager;

    @Override
    public Page<MateInventoryTypeChangeLogInfo> queryMateInventoryTypeChangeLog(MateInventoryTypeChangeLogQueryRequest request) {
        return mateInventoryTypeChangeLogService.queryMateInventoryTypeChangeLog(request);
    }

    @Override
    public MateInventoryTypeChangeLogGetDetailResponse getMateInventoryTypeChangeLogById(Long mateInventoryTypeChangeLogId) {
        return mateInventoryTypeChangeLogService.getMateInventoryTypeChangeLogById(mateInventoryTypeChangeLogId);
    }

    @Override
    public List<MateInventoryTypeChangeLogInfo> listMateInventoryTypeChangeLog(MateInventoryTypeChangeLogQueryRequest request) {
        return mateInventoryTypeChangeLogService.listMateInventoryTypeChangeLog(request);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MateInventoryTypeChangeLogAddResponse addMateInventoryTypeChangeLog(MateInventoryTypeChangeLogAddRequest request) {
        MateInventoryTypeChangeLogAddResponse response = mateInventoryTypeChangeLogService.addMateInventoryTypeChangeLog(request);
        if (MateInventoryTypeChangeLogOrderStatusEnum.S2.eq(request.getOrderStatus())) {
            lock(response.getId());
        }
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MateInventoryTypeChangeLogUpdateResponse updateMateInventoryTypeChangeLog(MateInventoryTypeChangeLogUpdateRequest request) {
        MateInventoryTypeChangeLogUpdateResponse response = mateInventoryTypeChangeLogService.updateMateInventoryTypeChangeLog(request);
        if (MateInventoryTypeChangeLogOrderStatusEnum.S2.eq(request.getOrderStatus())) {
            lock(response.getId());
        }
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MateInventoryTypeChangeLogDeleteResponse deleteMateInventoryTypeChangeLog(Long id) {
        MateInventoryTypeChangeLog changeLog = mateInventoryTypeChangeLogMapper.selectById(id);
        if (MateInventoryTypeChangeLogOrderStatusEnum.S3.eq(changeLog.getOrderStatus())) {
            throw new BusinessException(CommonRespCode.SYSTEM_ERR, "订单已完成，无法撤销");
        }
        if (MateInventoryTypeChangeLogOrderStatusEnum.S2.eq(changeLog.getOrderStatus())) {
            // 需要释放库存
            List<MateInventoryTypeChangeLogDetail> changeLogDetails = mateInventoryTypeChangeLogDetailMapper.selectList(
                    new LambdaQueryWrapper<MateInventoryTypeChangeLogDetail>()
                            .eq(MateInventoryTypeChangeLogDetail::getOrderNo, changeLog.getOrderNo())
            );
            releaseLock(changeLog, changeLogDetails);
        }
        return mateInventoryTypeChangeLogService.deleteMateInventoryTypeChangeLog(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approvedMateInventoryTypeChangeLog(Long id) {
        MateInventoryTypeChangeLog changeLog = mateInventoryTypeChangeLogMapper.selectById(id);
        if (!MateInventoryTypeChangeLogOrderStatusEnum.S2.eq(changeLog.getOrderStatus())) {
            throw new BusinessException(CommonRespCode.SYSTEM_ERR, "当前订单状态无法审批通过");
        }
        mateInventoryTypeChangeLogService.setOrderStatus(id, MateInventoryTypeChangeLogOrderStatusEnum.S3.getIntValue());

        List<MateInventoryTypeChangeLogDetail> changeLogDetails = mateInventoryTypeChangeLogDetailMapper.selectList(
                new LambdaQueryWrapper<MateInventoryTypeChangeLogDetail>()
                        .eq(MateInventoryTypeChangeLogDetail::getOrderNo, changeLog.getOrderNo())
        );
        releaseLock(changeLog, changeLogDetails);
        // 出库,入库
        Map<Long, Long> map = mateInventoryManager.changeMateInventoryType(changeLog, changeLogDetails);
        map.forEach((detailId, afterMateInventoryId) -> {
            mateInventoryTypeChangeLogDetailMapper.update(null,
                    new LambdaUpdateWrapper<MateInventoryTypeChangeLogDetail>()
                            .eq(MateInventoryTypeChangeLogDetail::getId, detailId)
                            .set(MateInventoryTypeChangeLogDetail::getAfterMateInventoryId, afterMateInventoryId)
            );
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refuseMateInventoryTypeChangeLog(Long id) {
        MateInventoryTypeChangeLog changeLog = mateInventoryTypeChangeLogMapper.selectById(id);
        if (!MateInventoryTypeChangeLogOrderStatusEnum.S2.eq(changeLog.getOrderStatus())) {
            throw new BusinessException(CommonRespCode.SYSTEM_ERR, "当前订单状态无法审批拒绝");
        }
        mateInventoryTypeChangeLogService.setOrderStatus(id, MateInventoryTypeChangeLogOrderStatusEnum.S1.getIntValue());
        List<MateInventoryTypeChangeLogDetail> changeLogDetails = mateInventoryTypeChangeLogDetailMapper.selectList(
                new LambdaQueryWrapper<MateInventoryTypeChangeLogDetail>()
                        .eq(MateInventoryTypeChangeLogDetail::getOrderNo, changeLog.getOrderNo())
        );
        releaseLock(changeLog, changeLogDetails);
    }

    private void lock(Long id) {
        // 锁定库存
        MateInventoryTypeChangeLog changeLog = mateInventoryTypeChangeLogMapper.selectById(id);
        List<MateInventoryTypeChangeLogDetail> changeLogDetails = mateInventoryTypeChangeLogDetailMapper.selectList(
                new LambdaQueryWrapper<MateInventoryTypeChangeLogDetail>()
                        .eq(MateInventoryTypeChangeLogDetail::getOrderNo, changeLog.getOrderNo())
        );
        List<MateInventoryLockLogAddRequest> requests = new ArrayList<>();
        for (MateInventoryTypeChangeLogDetail changeLogDetail : changeLogDetails) {
            MateInventoryLockLogAddRequest request = new MateInventoryLockLogAddRequest();
            request.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
            request.setSourceOrderNo(changeLog.getOrderNo());
            request.setSourceDetailOrderNo(changeLog.getOrderNo() + changeLogDetail.getId());
            request.setSourceOrderType(SubjectEnum.T122.getCode());
            request.setSubject(SubjectEnum.T122.getCode());
            request.setMateInventoryId(changeLogDetail.getBeforeMateInventoryId());
            request.setLockQty(changeLogDetail.getQty());
            requests.add(request);
        }
        mateInventoryManager.lockMateInventory(requests);
    }

    private void releaseLock(MateInventoryTypeChangeLog changeLog, List<MateInventoryTypeChangeLogDetail> changeLogDetails) {
        List<MateInventoryLockLogAddRequest> requests = new ArrayList<>();
        for (MateInventoryTypeChangeLogDetail changeLogDetail : changeLogDetails) {
            MateInventoryLockLogAddRequest request = new MateInventoryLockLogAddRequest();
            request.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
            request.setSourceOrderNo(changeLog.getOrderNo());
            request.setSourceDetailOrderNo(changeLog.getOrderNo() + changeLogDetail.getId());
            request.setSourceOrderType(SubjectEnum.T122.getCode());
            request.setSubject(SubjectEnum.T122.getCode());
            request.setMateInventoryId(changeLogDetail.getBeforeMateInventoryId());
            request.setLockQty(changeLogDetail.getQty());
            requests.add(request);
        }
        mateInventoryManager.releaseLockMateInventory(requests);
    }

    @Override
    public Page<MateInventoryTypeChangeLogModeInfo> queryMateInventoryTypeChangeLogMode(MateInventoryTypeChangeLogQueryModeRequest request) {
        return mateInventoryTypeChangeLogService.queryMateInventoryTypeChangeLogMode(request);
    }
}